package jt.classic.system.objectquery;

import jt.classic.system.ISystem;
import jt.classic.system.ISystemException;
import jt.classic.system.objectquery.impl.ObjectQueryImpl;
import jt.classic.system.objectquery.impl.ObjectQueryItemImpl;
import jt.classic.system.tablequery.TableQuery;
import jt.classic.system.workflow.WObject;
import jt.classic.system.workflow.WObjectRegister;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import org.limp.basework.Column;
import org.limp.basework.SimpleBean;
import org.limp.basework.Table;
import org.limp.basework.analyzer.TableRegisterCenter;
import org.limp.basework.console.XSystemConfig;

import org.limp.mine.StringTool;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * 表单对象查询注册
 *
 * @author mido
 *
 */
public final class ObjectQueryRegister {
    private static ObjectQueryRegister register;
    private List list;
    private Map fileMap;
    private Map info;
    private String encoding = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_CHARSETNAME);
    private OutputFormat format;

    private ObjectQueryRegister() {
        info = new HashMap();
        fileMap = new HashMap();
        list = new ArrayList();

        this.format = OutputFormat.createPrettyPrint();
        this.format.setEncoding(encoding); //设置XML文档的编码类型
        this.format.setSuppressDeclaration(false);
        this.format.setIndent(true); //设置是否缩进
        this.format.setIndent(" "); //以空格方式实现缩进
        this.format.setNewlines(true); //设置是否换行
    }

    public synchronized static ObjectQueryRegister getInstance() {
        if (register == null) {
            register = new ObjectQueryRegister();
        }

        return register;
    }

    public synchronized void init() {
        if (this.info.isEmpty()) {
            this.info.clear();
        }

        if (!this.list.isEmpty()) {
            this.list.clear();
        }

        if (!this.fileMap.isEmpty()) {
            this.fileMap.clear();
        }

        //DocumentHelper.createElement(arg0)
        String systemHome = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_SYSTEM_HOME);

        File folder = new File(systemHome, "conf" + File.separator + "queryO");

        if (folder.isDirectory()) {
            File[] files = folder.listFiles(new QueryOFileFilter());

            if ((files != null) && (files.length > 0)) {
                QueryOFiles qof = QueryOFiles.getInstance();

                for (int i = 0; i < files.length; i++) {
                    try {
                        SAXReader reader = new SAXReader();
                        Document document = reader.read(files[i]);

                        /*object-query元素*/
                        Iterator iter = document.getRootElement()
                                                .elementIterator("query");

                        while (iter.hasNext()) {
                            Element element = (Element) iter.next();
                            ObjectQuery query = this.initObjectQuery(element);

                            this.info.put(query.id(), query);
                            this.list.add(query);
                            this.fileMap.put(query.id(), files[i].getPath());
                        }

                        qof.setQueryFileLastModified(files[i].getName(),
                            files[i].lastModified());
                    } catch (Exception ex) {
                        ISystem.catchException(this, ex);
                    }
                }
            }
        }
    }

    /**
     * 重新加载配置文件
     * @param file
     */
    public synchronized void recallQueryFile(File file) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            /*object-query元素*/
            Iterator iter = document.getRootElement().elementIterator("query");

            while (iter.hasNext()) {
                Element element = (Element) iter.next();
                ObjectQuery query = this.initObjectQuery(element);

                this.info.put(query.id(), query);

                if ((this.list != null) && !this.list.isEmpty()) {
                    for (int i = 0; i < this.list.size(); i++) {
                        ObjectQuery temp = (ObjectQuery) this.list.get(i);

                        if (temp.id().equals(query.id())) {
                            this.list.set(i, query);
                        }
                    }
                }
            }

            QueryOFiles qof = QueryOFiles.getInstance();
            qof.setQueryFileLastModified(file.getName(), file.lastModified());
        } catch (Exception ex) {
            ISystem.catchException(this, ex);
        }
    }

    /**
     * 初始化表单对象
     *
     * @param element 表单对象元素
     * @return WObjectQuery 表单对象
     */
    private ObjectQuery initObjectQuery(Element element) {
        ObjectQuery query = new ObjectQueryImpl();

        String id = element.attributeValue("ID");
        String name = StringTool.checkString(element.elementText("name"));
        String object = StringTool.checkString(element.elementText("object"));
        String desc = StringTool.checkString(element.elementText("desc"));
        String jsurl = StringTool.checkString(element.elementText("jsurl"));
        String cssurl = StringTool.checkString(element.elementText("cssurl"));
        String queryurl = StringTool.checkString(element.elementText("queryurl"));
        String resulturl = StringTool.checkString(element.elementText(
                    "resulturl"));

        String session = StringTool.checkString(element.elementText("session"), "0");
        String showchk = StringTool.checkString(element.elementText("showchk"), "0");
        String createstime = StringTool.checkString(element.elementText(
                    "createstime"));
        String createetime = StringTool.checkString(element.elementText(
                    "createetime"));
        String defaultlist = StringTool.checkString(element.elementText(
                    "defaultlist"));
        String export = StringTool.checkString(element.elementText("export"), "");

        query.getResource().put("id", id);
        query.getResource().put("jsurl", jsurl);
        query.getResource().put("cssurl", cssurl);
        query.getResource().put("name", name);
        query.getResource().put("desc", desc);
        query.getResource().put("queryurl", queryurl);
        query.getResource().put("resulturl", resulturl);

        query.getResource().put("session", session);
        query.getResource().put("showchk", showchk);
        query.getResource().put("createstime", createstime);
        query.getResource().put("createetime", createetime);
        query.getResource().put("defaultlist", defaultlist);
        query.getResource().put("export", export);

        try {
            WObjectRegister register = WObjectRegister.getInstance();
            WObject obj = register.findWObject(object);
            query.getResource().put("object", obj);
        } catch (Exception ex) {
            ISystem.catchException(this, ex);
        }

        /*权限范围*/
        Element purviewItem = element.element("purview-item");

        String purview = "";

        String purviewname = "";

        String purviewstring = "";

        if (purviewItem != null) {
            Iterator purviewitems = purviewItem.elementIterator("item");

            while (purviewitems.hasNext()) {
                Element itemElement = (Element) purviewitems.next();

                String pid = StringTool.checkString(itemElement.attributeValue(
                            "id"));

                String pname = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                String ptype = StringTool.checkString(itemElement.attributeValue(
                            "type"));

                purview += (pid + "," + ptype + ";");

                purviewstring += (pid + "," + pname + "," + ptype + ";");

                purviewname += pname;

                if (ptype.equals("role")) {
                    purviewname += "(角色),";
                } else if (ptype.equals("group")) {
                    purviewname += "(组),";
                } else if (ptype.equals("user")) {
                    purviewname += "(用户),";
                }
            }

            purview = purview.substring(0, purview.length() - 1);
            purviewstring = purviewstring.substring(0,
                    purviewstring.length() - 1);
            purviewname = purviewname.substring(0, purviewname.length() - 1);
        }

        query.getResource().put("purview", purview);
        query.getResource().put("purviewname", purviewname);
        query.getResource().put("purviewstring", purviewstring);

        Element handleItem = element.element("handle-item");

        if (handleItem != null) {
            String insert = StringTool.checkString(handleItem.elementText(
                        "insert"), "no");
            String view = StringTool.checkString(handleItem.elementText("view"),
                    "no");
            String update = StringTool.checkString(handleItem.elementText(
                        "update"), "no");
            String delete = StringTool.checkString(handleItem.elementText(
                        "delete"), "no");
            String purview1 = StringTool.checkString(handleItem.elementText(
                        "purview"), "no");
            String export1 = StringTool.checkString(handleItem.elementText(
                        "export"), "no");
            String copy = StringTool.checkString(handleItem.elementText("copy"),
                    "no");

            Map handleMap = new HashMap();
            handleMap.put("insert", insert);
            handleMap.put("view", view);
            handleMap.put("update", update);
            handleMap.put("delete", delete);
            handleMap.put("purview", purview1);
            handleMap.put("export", export1);
            handleMap.put("copy", copy);

            query.getResource().put("handleMap", handleMap);
        }

        Element queryItem = element.element("query-item");

        if (queryItem != null) {
            Iterator queryitems = queryItem.elementIterator("item");

            List queryitemlist = new ArrayList();

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (queryitems.hasNext()) {
                ObjectQueryItem item = new ObjectQueryItemImpl();

                Element itemElement = (Element) queryitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                Table table = tableRegister.findTable(tableName);

                Column column = null;

                try {
                    column = table.column(columnName);
                } catch (Exception ex) {
                    ISystem.catchException(this, ex);
                }

                item.getResource().put("fieldName", columnName);
                item.getResource().put("column", column);
                item.getResource().put("class",
                    StringTool.checkString(itemElement.attributeValue("class")));
                item.getResource().put("label",
                    StringTool.checkString(itemElement.attributeValue("label")));

                /*              item.getResource().put("tableName",
                                  StringTool.checkString(itemElement.attributeValue(
                                          "tableName")));*/
                item.getResource().put("type",
                    StringTool.checkString(itemElement.attributeValue("type")));
                item.getResource().put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.getResource().put("mode",
                    StringTool.checkString(itemElement.attributeValue("mode")));
                item.getResource().put("pointId",
                    StringTool.checkString(itemElement.attributeValue("pointId")));
                item.getResource().put("pointName",
                    StringTool.checkString(itemElement.attributeValue(
                            "pointName")));
                item.getResource().put("need",
                    StringTool.checkString(itemElement.attributeValue("need")));
                item.getResource().put("idx",
                    StringTool.checkString(itemElement.attributeValue("idx")));

                item.reload(null);

                queryitemlist.add(item);
            }

            ItemComparator comp = new ItemComparator();

            Collections.sort(queryitemlist, comp);

            query.getResource().put("querylist", queryitemlist);
        }

        Element resultItem = element.element("result-item");

        if (resultItem != null) {
            Iterator resultitems = resultItem.elementIterator("item");

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            List viewitemlist = new ArrayList();

            while (resultitems.hasNext()) {
                ObjectQueryItem item = new ObjectQueryItemImpl();

                Element itemElement = (Element) resultitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                String alien = StringTool.checkString(itemElement.attributeValue(
                            "alien"));

                if (!alien.equals("1")) {
                    Table table = tableRegister.findTable(tableName);

                    Column column = null;

                    try {
                        column = table.column(columnName);
                    } catch (Exception ex) {
                        ISystem.catchException(this, ex);
                    }

                    item.getResource().put("column", column);
                }

                String clazz = StringTool.checkString(itemElement.attributeValue(
                            "class"));

                if (clazz.equals("")) {
                    clazz = columnName;
                }

                item.getResource().put("fieldName", columnName);
                item.getResource().put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.getResource().put("class", clazz);
                item.getResource().put("label",
                    StringTool.checkString(itemElement.attributeValue("label")));
                item.getResource().put("idx",
                    StringTool.checkString(itemElement.attributeValue("idx")));
                item.getResource().put("alien", alien);
                item.getResource().put("show",
                    StringTool.checkString(itemElement.attributeValue("show")));

                item.reload(null);

                viewitemlist.add(item);
            }

            ItemComparator comp = new ItemComparator();

            Collections.sort(viewitemlist, comp);

            query.getResource().put("viewlist", viewitemlist);
        }

        Element restraintItem = element.element("restraint-item");

        if (restraintItem != null) {
            Iterator restraintitems = restraintItem.elementIterator("item");

            List restraintitemlist = new ArrayList();

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (restraintitems.hasNext()) {
                ObjectQueryItem item = new ObjectQueryItemImpl();

                Element itemElement = (Element) restraintitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                Table table = tableRegister.findTable(tableName);

                Column column = null;

                try {
                    column = table.column(columnName);
                } catch (Exception ex) {
                    ISystem.catchException(this, ex);
                }

                item.getResource().put("column", column);
                item.getResource().put("fieldName", columnName);

                /*              item.getResource().put("tableName",
                                  StringTool.checkString(itemElement.attributeValue(
                                          "tableName")));*/
                item.getResource().put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.getResource().put("mode",
                    StringTool.checkString(itemElement.attributeValue("mode")));

                item.reload(null);

                restraintitemlist.add(item);
            }

            query.getResource().put("restraintlist", restraintitemlist);
        }

        query.reload(null);

        return query;
    }

    /**
     * 获取查询定义
     * @param id 查询定义key
     * @return ObjectQuery
     * @throws ISystemException
     */
    public synchronized ObjectQuery get(String id) throws ISystemException {
        return (ObjectQuery) this.info.get(id);
    }

    /**
     * 是否存在查询定义
     * @param id 查询定义key
     * @return boolean
     */
    public synchronized boolean contains(String id) {
        return this.info.containsKey(id);
    }

    /**
     * 对象查询设置列表
     * @param object 对象key
     * @return List
     * @throws ISystemException
     */
    public synchronized List list(String object) throws ISystemException {
        List temp = new ArrayList();

        if ((this.list != null) && !this.list.isEmpty()) {
            for (int i = 0; i < this.list.size(); i++) {
                ObjectQuery query = (ObjectQuery) this.list.get(i);

                if (query.iobject().ikey().equals(object)) {
                    temp.add(query);
                }
            }
        }

        return temp;
    }

    /**
     * 对象查询设置列表(所有)
     * @return List
     * @throws ISystemException
     */
    public synchronized List list() throws ISystemException {
        return new ArrayList(this.list);
    }

    /**
     * 增加对象查询
     *
     * @param xmlscript 对象查询脚本
     * @throws ISystemException
     */
    public synchronized void add(String xmlscript) throws ISystemException {
        String systemHome = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_SYSTEM_HOME);

        File file = new File(new File(systemHome,
                    "conf" + File.separator + "queryO"), "default.queryO");

        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            Element root = document.getRootElement();

            Document tempDoc = DocumentHelper.parseText(xmlscript);

            Element newElement = (Element) tempDoc.getRootElement().elements()
                                                  .get(0);

            Element cc = newElement.createCopy();

            root.add(cc);
            this.writeXML(file, root.getDocument());

            this.recallQueryFile(file);
        } catch (Exception ex) {
            throw new ISystemException("add object query error.", ex);
        }
    }

    /**
     * 增加对象查询
     *
     * @param xmlscript 对象查询脚本
     * @throws ISystemException
     */
    public synchronized void update(String id, String xmlscript)
        throws ISystemException {
        String filePath = (String) this.fileMap.get(id);

        File file = new File(filePath);

        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            Element root = document.getRootElement();

            Element orgElement = root.elementByID(id);

            if (orgElement != null) {
                root.remove(orgElement);

                Document tempDoc = DocumentHelper.parseText(xmlscript);

                Element newElement = (Element) tempDoc.getRootElement()
                                                      .elements().get(0);

                Element cc = newElement.createCopy();

                root.add(cc);
                this.writeXML(file, root.getDocument());

                this.recallQueryFile(file);
            }
        } catch (Exception ex) {
            throw new ISystemException("update object query error.", ex);
        }
    }

    /**
     * 删除对象查询设置
     *
     * @param id 对象查询ID
     * @throws ISystemException
     */
    public synchronized void remove(String id) throws ISystemException {
        String filePath = (String) this.fileMap.get(id);

        File file = new File(filePath);

        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            Element element = document.getRootElement().elementByID(id);

            if (element != null) {
                document.getRootElement().remove(element);
                this.writeXML(file, document);

                this.info.remove(id);

                this.fileMap.remove(id);

                if ((this.list != null) && !this.list.isEmpty()) {
                    for (int i = 0; i < this.list.size(); i++) {
                        ObjectQuery temp = (ObjectQuery) this.list.get(i);

                        if (temp.id().equals(id)) {
                            this.list.remove(i);

                            break;
                        }
                    }
                }

                QueryOFiles qof = QueryOFiles.getInstance();
                qof.setQueryFileLastModified(file.getName(), file.lastModified());
            }
        } catch (Exception ex) {
            throw new ISystemException("remove object query error.", ex);
        }
    }

    /**
     * 写消息存储文件内容
     * @param file 文件
     * @param document 内容
     * @return boolean
     */
    private boolean writeXML(File file, Document document)
        throws ISystemException {
        XMLWriter writer = null;
        boolean rnt = false;

        try {
            writer = new XMLWriter(new OutputStreamWriter(
                        new FileOutputStream(file), encoding), format);
            writer.write(document);
        } catch (Exception ex) {
            throw new ISystemException("write query.xml error.", ex);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (Exception ex) {
                    ex.printStackTrace(System.out);
                }
            }

            rnt = true;
        }

        return rnt;
    }

    /**
     * 数据字典项排列比较器
     *
     * @author mido
     *
     */
    private class ItemComparator implements Comparator {
        public int compare(Object o1, Object o2) {
            // TODO Auto-generated method stub
            SimpleBean c1 = (SimpleBean) o1;
            SimpleBean c2 = (SimpleBean) o2;

            String c1idx = StringTool.checkString(c1.getResource().get("idx"),
                    "");

            String c2idx = StringTool.checkString(c2.getResource().get("idx"),
                    "");

            if (c1idx.compareTo(c2idx) < 0) {
                return -1;
            } else {
                if (c1idx.compareTo(c2idx) == 0) {
                    return 0;
                } else {
                    return 1;
                }
            }
        }
    }

    /**
     * 对象查询注册文件过滤器
     * @author mido
     *
     */
    private class QueryOFileFilter implements FileFilter {
        /**
        *
        * 文件类型过滤
        * @param file 注册文件
        * @return boolean
        *
        */
        public boolean accept(File file) {
            if (file.isFile()) {
                /*文件名称*/
                String fileName = file.getName();

                /*文件扩展名*/
                String expandName = ((fileName.lastIndexOf(".") > -1) &&
                    (fileName.lastIndexOf(".") < fileName.length()))
                    ? fileName.substring(fileName.lastIndexOf(".") + 1) : "";

                return expandName.equals("queryO");
            }

            return false;
        }
    }
}
